#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
    Part of Seagull - The Pyhon Pages engine
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    sessions:
      Dictionary objects where the session information should reside
      in between requests. Some managers will write the session information
      to a database/file storage.
"""
__author__ = 'Jonathan Slenders <jonathan at slenders dot be>'
__license__ = 'GNU LGPL'



import os
import threading
import pickle

################################################################
# Session manager stub
################################################################

class SessionManager(object):
	class SessionStatus(object):
		"""
		Keeps reference count for session objects.  Sessions are
		stored to disk, only after the referenc count turns zero.
		"""
		def __init__(self):
			self.refs = 0 # Loaded by this many threads
			self.session = { }

		def __str__(self):
			return 'session(refs=%s, content=%s)' % (self.refs, self.session)

	def __init__(self):
		self.__in_memory = { } # Session objects in memory
		self.__session_lock = threading.RLock()

	def store_session(self, id):
		""" Store session (refcount -- )"""

		self.__session_lock.acquire()

		if self.__in_memory.has_key(id):
			status = self.__in_memory[id]
			status.refs -= 1

			if status.refs == 0:
				self._store_session_body(id, status.session)
				del self.__in_memory[id]

		self.__session_lock.release()

	def load_session(self, id):
		""" Load session (refcount ++) """

		self.__session_lock.acquire()

		if self.__in_memory.has_key(id):
			status = self.__in_memory[id]
		else:
			status = self.SessionStatus()
			status.session = self._load_session_body(id)
			self.__in_memory[id] = status

		status.refs += 1

		self.__session_lock.release()
		return status.session

	def session_exists(self, id):
		raise 'Not implemented'

	def _store_session_body(self, id, value):
		""" Actual implementation for storing to persistent storage """
		raise 'Not implemented'

	def _load_session_body(self, id):
		""" Actual implementation for loading from persistent storage """
		raise 'Not implemented'

################################################################
# Implementations
################################################################

class InMemorySessionManager(SessionManager):
	def __init__(self):
		SessionManager.__init__(self)
		self.__sessions = { }

	def session_exists(self, id):
		return id in self.__sessions

	def _load_session_body(self, id):
		if id in self.__sessions:
			return self.__sessions[id]
		else:
			return { }

	def _store_session_body(self, id, value):
		self.__sessions[id] = value

class FileSessionManager(SessionManager):
	def __init__(self):
		SessionManager.__init__(self)

	def session_exists(self, id):
		return os.path.exists('model/sessions/%s.session' % id)

	def _load_session_body(self, id):
		if os.path.exists('model/sessions/%s.session' % id):
			input = open('model/sessions/%s.session' % id, 'rb')
			session = pickle.load(input)
			input.close()
			if session:
				return session
		return { }

	def _store_session_body(self, id, value):
		output = open('model/sessions/%s.session' % id, 'wb')
		pickle.dump(value, output)
		output.close()
